Skip to content

fix: Handle configuration changes during WebAuth flow to prevent memory leak#941

Open
utkrishtsahu wants to merge 1 commit intov4_developmentfrom
SDK-6233-The-SDK-doesn-t-handle-configuration-changes-correctly-on-device-rotation-and-causes-a-memory-leak
Open

fix: Handle configuration changes during WebAuth flow to prevent memory leak#941
utkrishtsahu wants to merge 1 commit intov4_developmentfrom
SDK-6233-The-SDK-doesn-t-handle-configuration-changes-correctly-on-device-rotation-and-causes-a-memory-leak

Conversation

@utkrishtsahu
Copy link
Contributor

@utkrishtsahu utkrishtsahu commented Mar 24, 2026

Changes

When the Activity is destroyed during a WebAuth login or logout flow due to a configuration change (e.g. device rotation, locale change, dark mode toggle), the SDK previously retained a strong reference to the destroyed Activity via the static WebAuthProvider.managerInstance → OAuthManager/LogoutManager → callback chain, causing a memory leak. Additionally, the authentication result was delivered to the destroyed Activity's callback, which could crash or silently fail.

Root cause: WebAuthProvider.managerInstance is a static field. OAuthManager and LogoutManager held a strong reference to the callback, which captured the Activity/Fragment this. On configuration change, the old Activity was destroyed but never garbage collected because of this reference chain.

What changed:

  • OAuthManager: Changed callback storage from strong reference to WeakReference. When the callback is GC'd (Activity destroyed), the result is cached in WebAuthProvider.pendingLoginResult instead of being lost.
  • LogoutManager: Same WeakReference pattern applied. Pending results cached in WebAuthProvider.pendingLogoutResult.
  • WebAuthProvider: Added the following new public APIs:
    • consumePendingLoginResult(callback) — Checks for and delivers a cached login result to the provided callback. Returns true if a pending result was found and delivered.
    • consumePendingLogoutResult(callback) — Same for logout results.
    • PendingResult<S, E> (internal sealed class) — Represents a cached Success or Failure result.
  • EXAMPLES.md: Added "Handling Configuration Changes During Authentication" section with usage example.
  • V4_MIGRATION_GUIDE.md: Added documentation under "New APIs" section.

Usage:

override fun onResume() {
    super.onResume()
    WebAuthProvider.consumePendingLoginResult(loginCallback)
    WebAuthProvider.consumePendingLogoutResult(logoutCallback)
}

No existing public APIs were removed, deprecated, or changed in signature. The suspend fun await() API is unaffected since it doesn't capture the Activity in the callback chain.

Testing

Unit tests added (8 new tests in WebAuthProviderTest.kt):

shouldCacheLoginSuccessWhenCallbackIsGarbageCollected
shouldCacheLoginFailureWhenCallbackIsGarbageCollected
shouldCacheLogoutSuccessWhenCallbackIsGarbageCollected
shouldCacheLogoutFailureWhenCallbackIsGarbageCollected
shouldConsumePendingLoginResultAndReturnTrue
shouldReturnFalseWhenNoPendingLoginResult
shouldConsumePendingLogoutResultAndReturnTrue
shouldReturnFalseWhenNoPendingLogoutResult
All existing unit tests pass without modification.

Manual testing performed on Pixel 7a (Android 14):

  • WITHOUT fix: Rotated device during login → callback delivered to destroyed Fragment → crash: "Fragment not attached to a context". New Fragment never received the result.
  • WITH fix: Rotated device during login → result cached via pendingLoginResult → new Fragment recovered result via consumePendingLoginResult() in onResume() → Snackbar shown on correct live Fragment. No crash, no memory leak.

Checklist

@utkrishtsahu utkrishtsahu requested a review from a team as a code owner March 24, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant